package com.bms.cfcmms.core.module;

import com.bms.cfcmms.core.util.Utils;
import com.bms.cfcmms.model.system.module.Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;


/**
 * Created by carl on 2016/4/11.
 */
public class SqlGenerator {

    Logger log = LoggerFactory.getLogger(SqlGenerator.class);
    HttpServletRequest request;

    //key 数据库字段名  value pojo属性名
    Map<String, String> hasValueTableCoulmns = new HashMap<>();

    private Module module;

    //分页参数
    private Integer start;
    private Integer limit;

    //sql语句的类型：比如select语句、update语句、delete语句等
    private String sqlType;

    public SqlGenerator(String sqlType) {
        this.sqlType = sqlType;
    }

    /**
     * 获取sql语句.
     * <p>
     * <p>根据SqlGenerator对象中的初始化信息产生sql语句</p>
     *
     * @return 可执行的sql语句
     */
    public String makeSql() {
        if (SqlType.UPDATE.equals(this.sqlType)) {
            return getUpdateSql();
        }
        if (SqlType.SELECT.equals(this.sqlType)) {
            return getSelectSql();
        }
        if (SqlType.INSERT.equals(this.sqlType)) {
            return getInsertSql();
        }
        if (SqlType.DELETE.equals(this.sqlType)) {
            return getDeleteSql();
        }
        log.error("还不支持当前的sql语句：" + this.sqlType);
        return null;
    }

    /**
     * 构建查询语句的sql字符串.
     * <p>
     * <p>根据SqlGenerator中的信息来构建select sql语句</p>
     *
     * @return 返回一个可以使用的sql语句
     */
    private String getSelectSql() {

        StringBuilder sqlBuffer = new StringBuilder(String.valueOf(SqlType.SELECTALL));
        dealTableName(sqlBuffer);
        makeWhere(sqlBuffer);
        if (this.getStart() != null && this.getLimit() != null) {
            sqlBuffer.append(" ").append(Utils.QUERY_LIMIT_LIMIT).append(" ").append(this
                    .getStart().intValue())
                    .append(",").append(this.getLimit().intValue());
        }
        return sqlBuffer.toString();
    }

    private void makeWhere(StringBuilder sqlBuffer) {
        if (hasValueTableCoulmns.size() != 0) {
            //如果主键有值直接用主键去查找
            String primaryKey = hasValueTableCoulmns.get(module.getPrimaryKey());
            if (StringUtils.hasLength(primaryKey)) {
                sqlBuffer.append(SqlType.WHERE);
                sqlBuffer.append(module.getPrimaryKey());
                sqlBuffer.append("=:").append(primaryKey);
            } else {
                sqlBuffer.append(SqlType.WHERE );
                getKeyValueSql(sqlBuffer, "=:", " and ");
            }
        }
    }

    /**
     * 构建查询语句的sql字符串.
     * <p>
     * <p>根据SqlGenerator中的信息来构建delete sql语句</p>
     *
     * @return 返回一个可以使用的sql语句
     */
    private String getDeleteSql() {

        StringBuilder sqlBuffer = new StringBuilder("delete from ");
        dealTableName(sqlBuffer);
        makeWhere(sqlBuffer);

        return sqlBuffer.toString();
    }

    /**
     * 获得更新的sql语句.
     * <p>
     * <p>获取update类型的sql语句</p>
     *
     * @return sql语句
     */
    private String getUpdateSql() {
        StringBuilder sqlBuffer = new StringBuilder("update ");
        dealTableName(sqlBuffer);
        sqlBuffer.append(" set ");
        getKeyValueSql(sqlBuffer, "=:", ",");
        sqlBuffer.append(SqlType.WHERE)
                .append(module.getPrimaryKey())
                .append("=:")
                .append(hasValueTableCoulmns.get(module.getPrimaryKey()));
        return sqlBuffer.toString();
    }

    private void dealTableName(StringBuilder sqlBuffer) {
        if (Utils.hasLength(module.getTableName())) {
            sqlBuffer.append(module.getTableName());
        } else {
            sqlBuffer.append(module.getModuleName());
        }
    }

    /**
     * 获得插入的sql语句.
     * <p>
     * <p>获取insert类型的sql语句</p>
     *
     * @return sql语句
     */
    public String getInsertSql() {
        StringBuilder sqlBuffer = new StringBuilder("insert into ");
        dealTableName(sqlBuffer);
        sqlBuffer.append("(");
        getKeyValueSql(sqlBuffer, ",", ",");
        sqlBuffer.append(") value (");
        getKeyValueSql(sqlBuffer, ":", ",");
        sqlBuffer.append(")");

        return sqlBuffer.toString().trim();
    }

    /**
     * 获得带值的字符串.
     * <p>
     * <p>获取到有值的字段的字符串部分，类似于：
     * a=:a and b=:b 或者 a=:a, b=:b
     * </p>
     *
     * @param sqlBuffer sql缓存
     * @param str       拼接的字符串
     */
    private void getKeyValueSql(StringBuilder sqlBuffer, String conStr, String str) {
        int num = 0;

        Iterator<Map.Entry<String, String>> entries = hasValueTableCoulmns.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<String, String> entry = entries.next();
            if (SqlType.INSERT.equals(sqlType)) {
                if (!":".equals(conStr)) {
                    sqlBuffer.append(entry.getKey());
                } else {
                    sqlBuffer.append(conStr).append(entry.getValue());
                }
            } else {
                sqlBuffer.append(entry.getKey()).append(conStr).append(entry.getValue());
            }
            num++;
            if (num != hasValueTableCoulmns.size()) {
                sqlBuffer.append(str);
            }
        }
    }


    public Module getModule() {
        return module;
    }

    public void setModule(Module module) {
        this.module = module;
    }

    public Map<String, String> getHasValueTableCoulmns() {
        return hasValueTableCoulmns;
    }

    public void setHasValueTableCoulmns(Map<String, String> hasValueTableCoulmns) {
        this.hasValueTableCoulmns = hasValueTableCoulmns;
    }


    public Integer getStart() {
        return start;
    }

    public void setStart(Integer start) {
        this.start = start;
    }

    public Integer getLimit() {
        return limit;
    }

    public void setLimit(Integer limit) {
        this.limit = limit;
    }
}
